-- Copyright (c) 2025 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local skynet         = require 'skynet'
local class          = require 'mc.class'
local singleton      = require 'mc.singleton'
local mctp_callbacks = require 'infrastructure.callback.mctp_callbacks'
local spdm_component = require 'interface.discovery.spdm_component_manager'

local CONTROLLER_PATH_PATTERN = "/bmc/kepler/Systems/(%d+)/Storage/Controllers/Controller_1_(%w+)"
local COMPONENT_NAME_PATTERN  = "SpdmComponent_1_(%w+)"
local CHASSIS_ID              = 1
local COMPONENT_TYPE          = "Discrete"

local spdm_component_collection = class()

function spdm_component_collection:ctor(bus, responder_collection, spdm_auth)
    self.m_bus = bus
    self.m_responder_collection = responder_collection
    self.m_spdm_auth = spdm_auth
    self.m_collection = {}
    self.m_path_map = {}
    self.m_count = 0
end

function spdm_component_collection:init()
end

function spdm_component_collection:add_component(object, position)
    local index = string.match(object.object_name, COMPONENT_NAME_PATTERN)
    local obj = spdm_component.new(object, position, self.m_path_map[index], "SPDM_" .. tostring(self.m_count))
    self.m_collection[index] = obj
    self.m_count = self.m_count + 1

    mctp_callbacks.register_mctp_send_recv_cb(obj)

    skynet.fork_once(function()
        for _ = 1, 60 do -- 超时60秒
            if self.m_collection[index] and self.m_path_map[index] then
                self.m_responder_collection:new_responder(CHASSIS_ID, self.m_collection[index])
                self.m_responder_collection:new_component(CHASSIS_ID, self.m_collection[index],
                    self.m_path_map[index], COMPONENT_TYPE)
                pcall(function()
                    self.m_spdm_auth:do_auth(CHASSIS_ID, obj.device_name)
                end)
                break
            end
            skynet.sleep(100) -- 睡眠100 * 0.01秒
        end
    end)
end

function spdm_component_collection:register_component_path(path)
    local _, index = string.match(path or "", CONTROLLER_PATH_PATTERN)
    self.m_path_map[index] = path

    if not self.m_collection[index].inventory_path then
        self.m_collection[index].inventory_path = path
    end
end

function spdm_component_collection:get_component_by_device_name(device_name)
    for _, v in pairs(self.m_collection) do
        if v.device_name == device_name then
            return v
        end
    end

    return nil
end

return singleton(spdm_component_collection)